package com.lqwu.mallchatserver.user.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lqwu.mallchatserver.user.model.entry.User;
import com.lqwu.mallchatserver.user.service.UserService;
import com.lqwu.mallchatserver.user.service.WxMsgService;
import com.lqwu.mallchatserver.websocket.service.WebSocketService;
import com.lqwu.mallchatserver.websocket.service.adapter.TextBuilder;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Slf4j
public class WxMsgServiceImpl implements WxMsgService {
    @Value("${wx.mp.callback}")
    private String callback;

    // 授权链接(待拼接)
    private static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    // 扫码等待授权的集合(OpenId 和 Code 的关联)
    private static ConcurrentHashMap<String, Integer> WAIT_AUTHORIZE_MAP = new ConcurrentHashMap<>();

    @Resource
    private UserService userService;
    @Resource
    private WebSocketService webSocketService;

    /**
     * 用户扫码成功
     * @param wxMpService
     * @param wxMpXmlMessage
     * @return
     */
    @Override
    public WxMpXmlOutMessage scan(WxMpService wxMpService, WxMpXmlMessage wxMpXmlMessage) {
        // 1.获取 openId 和 事件码
        String openId = wxMpXmlMessage.getFromUser();
        // 事件码进行处理,将前缀 grscene_ 去掉
        String eventKey = wxMpXmlMessage.getEventKey();
        int code = Integer.parseInt(eventKey.replace("grscene_", ""));

        // 2.获取用户信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getOpenId, openId);
        User user = userService.getOne(queryWrapper);

        // 3.判断用户是否 存在 并 授权
        boolean registered = ObjectUtil.isNotNull(user);// 是否已注册
        boolean authorized = registered && StrUtil.isNotBlank(user.getAvatar());// 是否已授权
        if (registered && authorized){
            // 登陆成功的逻辑，通过 code 获得连接的 channel
            Boolean success = webSocketService.scanLoginSuccess(code, user.getId());
        }else if (registered){
            // 未注册,则注册
            User registeredUser = new User();
            registeredUser.setOpenId(openId);
            userService.register(registeredUser);
        }

        // 4.推送链接让用户授权
        // 加入到 扫码等待授权的集合中
        WAIT_AUTHORIZE_MAP.put(openId, code);
        // 返送消息——扫码中
        webSocketService.waitAuthorize(code);
        // 拼接授权链接
        String url = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), callback);
        return TextBuilder.build("请点击登录：<a href=\"" + url + "\">登录</a>", wxMpXmlMessage, wxMpService);
    }

    /**
     * 用户授权成功
     * @param userInfo
     */
    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        // 1.获取用户信息
        String openid = userInfo.getOpenid();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getOpenId, openid);
        User user = userService.getOne(queryWrapper);
        // 已授权，直接返回
        if (StrUtil.isNotBlank(user.getAvatar())){
            return;
        }
        // 2.保存用户授权信息到数据库
        String nickname = userInfo.getNickname();
        Integer sex = userInfo.getSex();
        String headImgUrl = userInfo.getHeadImgUrl();
        user.setAvatar(headImgUrl);
        user.setName(nickname);
        user.setSex(sex);
        boolean updated = userService.updateById(user);
        // 3.删除扫码等待授权的集合
        Integer removedCode = WAIT_AUTHORIZE_MAP.remove(openid);
        // 4.扫码成功，通过 code 获得连接的 channel
        webSocketService.scanLoginSuccess(removedCode, user.getId());
    }
}
